#include "stdafx.h"
#include "LuaState.h"

namespace LuaPerform
{
	LuaState::LuaState(void)
	{
		m_L = lua_open();
		luaopen_base(m_L);
	}

	LuaState::~LuaState(void)
	{
		lua_close(m_L);
		for (std::vector<void*>::iterator iter = m_CFunctionDLLs.begin(); iter != m_CFunctionDLLs.end(); ++iter)
			BaseFunction::DeleteModule(*iter);
	}

	void LuaState::OpenLuaLib(LuaLib libType)
	{
		if (libType & IO_Lib)
		{
			lua_pushcfunction(m_L, luaopen_io);
			lua_pushstring(m_L, LUA_IOLIBNAME);
			lua_call(m_L, 1, 0);
		}
		if (libType & Math_Lib)
			luaopen_math(m_L);
		if (libType & Table_Lib)
			luaopen_table(m_L);
		if (libType & System_Lib)
			luaopen_os(m_L);
		if (libType & String_Lib)
			luaopen_string(m_L);
	}

	void LuaState::RegistCFunction(std::string name, lua_CFunction func)
	{
		lua_pushcfunction(m_L, func);
		lua_setglobal(m_L, name.c_str());
	}

	int LuaState::Comply(std::string& script)
	{
		std::string closure = "function DBBF49157954464C884A8C4FE01B445D() C6BF1D037FE2488A8B283CFCD9B313C2 = {}";
		closure += " setmetatable(C6BF1D037FE2488A8B283CFCD9B313C2, {__index = _G}) ";
		closure += " setfenv(1, C6BF1D037FE2488A8B283CFCD9B313C2) return function() ";
		closure += "\r\n" + script + "\r\n";
		closure += " end end return DBBF49157954464C884A8C4FE01B445D()";
		if (luaL_loadstring(m_L, closure.c_str()) || lua_pcall(m_L, 0, 1, 0))
		{
			m_LastError = std::string("comply error: ") + lua_tostring(m_L, -1);
			lua_pop(m_L, 1);
			return -1;
		}
		return luaL_ref(m_L, LUA_REGISTRYINDEX);
	}

	bool LuaState::Execute(std::string& result)
	{
		if (lua_pcall(m_L, 0, 1, 0))
		{
			m_LastError = std::string("script runtime error: ") + lua_tostring(m_L, -1);
			lua_pop(m_L, 1);
			return false;
		}
		int type = lua_type(m_L, -1);
		switch(type)
		{
		case LUA_TBOOLEAN:
			result = lua_toboolean(m_L, -1) == 0 ? "false" : "true";
			break;
		case LUA_TNUMBER:
		case LUA_TSTRING:
			result = lua_tostring(m_L, -1);
			break;
		default:
			result = "";
			break;
		}
		lua_pop(m_L, 1);
		return true;
	}

	void LuaState::RegisterRefAt(int index)
	{
		lua_rawgeti(m_L, LUA_REGISTRYINDEX, index);
	}

	void LuaState::RegisterUnref(int index)
	{
		luaL_unref(m_L, LUA_REGISTRYINDEX, index);
	}

	std::string LuaState::LastError() const
	{
		return m_LastError;
	}

	bool LuaState::LoadCFunctionDLL(std::string& path)
	{
		void* pAddress;
		void* pModule = BaseFunction::FindFunctionFromModule(path, "LuaCFunction", &pAddress);
		if (pModule)
			m_CFunctionDLLs.push_back(pModule);
		else
			return false;
		((LuaCFunction)pAddress)(m_L);
		return true;
	}
}